#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>

using namespace std;

fstream fout;

vector<char> readFileBinary(const char* filename){
    vector<char> res;
    fstream fstream;
    auto type = ios_base::in | ios_base::binary | ios_base::ate;

    fstream.open(filename, type);

    size_t imageSize;
    if ((imageSize = fstream.tellg()) == -1u) {
        cout << "Cannot load "<<filename<<endl;
        fstream.close();
        return res;
    }
    res.resize(imageSize);
    fstream.seekg(0, std::ios::beg);
    fstream.read(res.data(), imageSize);
    fstream.close();
    return res;
}

std::string readFileString(const char* filename){
    stringstream ss;
    fstream fstream;
    auto type = ios_base::in;

    fstream.open(filename, type);

    string line;
    bool start = true;
    while( getline( fstream, line ) ) {
        if (!start){
            ss<<endl;
        }
        ss << line;
        start = false;
    }

    fstream.close();
    return ss.str();
}

void printRes(vector<char>& r, string resourceName){
    fout << "char "<<resourceName<<"[] = {";
    for (int i=0;i<r.size();i++){
        if (i>0){
            fout<< ',';
        }
        fout << (int)r[i];
    }

    fout << "};"<<std::endl;
}

void printResShader(string& r, string resourceName){

    fout << "std::make_pair<std::string,std::string>(\""<<resourceName<< "\",R\"(";

    fout<<r;

    fout << ")\"),\n";;
}

int main(int argc, char * argv[]){
    if (argc<=1){
        std::cout << "Usage:"<<std::endl;
        std::cout << "files_to_cpp [filename1] [resourcename1] [filename2] [resourcename2] ... [outputfile]"<<std::endl;
        std::cout << "files_to_cpp shader [filename1] [resourcename1] [filename2] [resourcename2] ... [outputfile]"<<std::endl;
        return -1;
    }
    fout.open(argv[argc-1], ios::out | ios::trunc );

    cout << "generating " << argv[argc-1] << endl;
    fout << "// autogenerated by"<<std::endl<<"// files_to_cpp";
    for (int i=1;i<argc;i++){
        fout<<" "<<argv[i];
    }
    fout<<endl;

    if (std::string("shader") == argv[1]){
        fout <<"#include <map>\n"
                "#include <utility>\n"
                "#include <string>\n"
                "\n"
                "std::map<std::string, std::string> builtInShaderSource  {"<<endl;
        for (int i=2;i<argc-1;i=i+2){
            auto filename = argv[i];
            auto resourcename = argv[i+1];
            auto res = readFileString(filename);
            cout << filename<<" " <<res.size()<<endl;
            printResShader(res, resourcename);

        }
        fout << "};";
    } else {
        fout<<"namespace { "<<endl;
        for (int i=1;i<argc-1;i=i+2){
            auto filename = argv[i];
            auto resourcename = argv[i+1];
            auto res = readFileBinary(filename);
            cout << filename<<" " <<res.size()<<endl;
            printRes(res, resourcename);

        }
        fout<<"}"<<endl;
    }

    fout.flush();
    fout.close();
    return 0;
}